/*********************************************************************
 * File Name          : lcd.c
 * Author             : WCH
 * Version            : V1.0.0
 * Date               : 2023/8/15
 * Description        : file for lcd screen.
 *********************************************************************************
* Copyright (c) 2023 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for 
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/

#include "lcd.h"
#include "debug.h"

static uint16_t width;
static uint16_t height;

#define LCD_SOFT_RESET          (0x01)
#define LCD_READ_ID             (0x04)
#define LCD_READ_DISPLAY_STATUS (0x09)
#define LCD_ON                  (0x28)
#define LCD_OFF                 (0x29)

#define LCD_SET_X               (0x2a)
#define LCD_SET_Y               (0x2B)
#define LCD_MEM_WRITE           (0x2C)
#define LCD_MEM_READ            (0x2e)

static uint16_t color_buffer[2][FILL_BUFFER_COUNT] = {0};

/*********************************************************************
 * @fn      LCD_WR_REG
 *
 * @brief   Write an 8-bit command to the LCD screen
 * 
 * @param   data - Command value to be written
 *
 * @return  none
 */
static void LCD_WR_REG(uint8_t data)
{
    LCD_CS_CLR;
    LCD_DC_CLR;
    SPI2_Write(data);
    LCD_CS_SET;
}

/*********************************************************************
 * @fn      LCD_WR_DATA
 *
 * @brief   Write an 8-bit data to the LCD screen
 * 
 * @param   data - the data to write
 * 
 */
static void LCD_WR_DATA(uint8_t data)
{
    LCD_CS_CLR;
    LCD_DC_SET;
    SPI2_Write(data);
    LCD_CS_SET;
}

/*********************************************************************
 * @fn      LCD_WriteReg
 * 
 * @brief   write a data to the register
 * 
 * @param   LCD_Reg - register address
 *          LCD_RegValue - the data to write
 * 
 * @return  none
 */
static void LCD_WriteReg(uint8_t LCD_Reg, uint8_t LCD_RegValue)
{
    LCD_WR_REG(LCD_Reg);
    LCD_WR_DATA(LCD_RegValue);
}

/*********************************************************************
 * @fn      Lcd_WriteData_16Bit
 * 
 * @brief   write two bytes to the lcd screen
 * 
 * @param   Data - the data to write
 * 
 * @return  none
 */
void Lcd_WriteData_16Bit(uint16_t Data)
{
    LCD_CS_CLR;
    LCD_DC_SET;
    SPI2_Write(Data >> 8);
    SPI2_Write(Data);
    LCD_CS_SET;
}

/*********************************************************************
 * @fn      LCD_GPIOInit
 * 
 * @brief   Configuring the control gpio for the lcd screen
 * 
 * @return  none
 */
void LCD_GPIOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(LCD_LED_RCC, ENABLE);
    RCC_APB2PeriphClockCmd(LCD_DC_RCC, ENABLE);
    RCC_APB2PeriphClockCmd(LCD_RST_RCC, ENABLE);
    RCC_APB2PeriphClockCmd(LCD_CS_RCC, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = LCD_LED_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(LCD_LED_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = LCD_DC_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(LCD_DC_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = LCD_RST_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(LCD_RST_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = LCD_CS_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(LCD_CS_PORT, &GPIO_InitStructure);
}

/*********************************************************************
 * @fn      LCD_RESET
 * 
 * @brief   reset the lcd screen by the rst pin
 * 
 * @return  none
 */
void LCD_RESET(void)
{
    LCD_RST_CLR;
    Delay_Ms(100);
    LCD_RST_SET;
    Delay_Ms(50);
}








lcd_init_cmd_t st7789_init_cmds[] = {



#if 1
       /* Memory Data Access Control, MX=MV=1, MY=ML=MH=0, RGB=0 */
       {0x36, {(1<<5)|(1<<6)}, 1},
       /* Interface Pixel Format, 16bits/pixel for RGB/MCU interface */
       {0x3A, {0x05}, 1},
       /* Porch Setting */
       {0xB2, {0x0c, 0x0c, 0x00, 0x33, 0x33}, 5},
       /* Gate Control, Vgh=13.65V, Vgl=-10.43V */
       {0xB7, {0x35}, 1},
       /* VCOM Setting, VCOM=1.175V */
       {0xBB, {0x19}, 1},
       /* LCM Control, XOR: BGR, MX, MH */
       {0xC0, {0x2C}, 1},
       /* VDV and VRH Command Enable, enable=1 */
       {0xC2, {0x01}, 1},
       /* VRH Set, Vap=4.4+... */
       {0xC3, {0x12}, 1},
       /* VDV Set, VDV=0 */
       {0xC4, {0x20}, 1},
       /* Frame Rate Control, 60Hz, inversion=0 */
       {0xC6, {0x0f}, 1},
       /* Power Control 1, AVDD=6.8V, AVCL=-4.8V, VDDS=2.3V */
       {0xD0, {0xA4, 0xA1}, 1},

       /* Positive Voltage Gamma Control */
       {0xE0, {0xD0, 0x00, 0x05, 0x0E, 0x15, 0x0D, 0x37, 0x43, 0x47, 0x09, 0x15, 0x12, 0x16, 0x19}, 14},
       /* Negative Voltage Gamma Control */
       {0xE1, {0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19}, 14},
       /* Sleep Out */
       {0x11, {0}, 0x80},
       {0x21, {0}, 0x80},
       /* Display On */
       {0x29, {0}, 0x80},
       {0, {0}, 0xff}

#endif
   };

/*********************************************************************
 * @fn      LCD_Init
 * 
 * @brief   Initialization LCD screen
 * 
 * @return  none
 */
void LCD_Init(void)
{
    SPI2_Init();
    SPI2_DMA_Init();
    LCD_GPIOInit();
    LCD_RESET();
    LCD_LED_SET;

#if ST7789
//    LCD_WR_REG(0xCF);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0xC9);  //C1
//    LCD_WR_DATA(0X30);
//    LCD_WR_REG(0xED);
//    LCD_WR_DATA(0x64);
//    LCD_WR_DATA(0x03);
//    LCD_WR_DATA(0X12);
//    LCD_WR_DATA(0X81);
//    LCD_WR_REG(0xE8);
//    LCD_WR_DATA(0x85);
//    LCD_WR_DATA(0x10);
//    LCD_WR_DATA(0x7A);
//    LCD_WR_REG(0xCB);
//    LCD_WR_DATA(0x39);
//    LCD_WR_DATA(0x2C);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x34);
//    LCD_WR_DATA(0x02);
//    LCD_WR_REG(0xF7);
//    LCD_WR_DATA(0x20);
//    LCD_WR_REG(0xEA);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_REG(0xC0);   //Power control
//    LCD_WR_DATA(0x1B);  //VRH[5:0]
//    LCD_WR_REG(0xC1);   //Power control
//    LCD_WR_DATA(0x00);  //SAP[2:0];BT[3:0] 01
//    LCD_WR_REG(0xC5);   //VCM control
//    LCD_WR_DATA(0x30);  //3F
//    LCD_WR_DATA(0x30);  //3C
//    LCD_WR_REG(0xC7);   //VCM control2
//    LCD_WR_DATA(0XB7);
//    LCD_WR_REG(0x36);  // Memory Access Control
//    LCD_WR_DATA(0x08);
//    LCD_WR_REG(0x3A);
//    LCD_WR_DATA(0x55);
//    LCD_WR_REG(0xB1);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x1A);
//    LCD_WR_REG(0xB6);  // Display Function Control
//    LCD_WR_DATA(0x0A);
//    LCD_WR_DATA(0xA2);
//    LCD_WR_REG(0xF2);  // 3Gamma Function Disable
//    LCD_WR_DATA(0x00);
//    LCD_WR_REG(0x26);  //Gamma curve selected
//    LCD_WR_DATA(0x01);
//    LCD_WR_REG(0xE0);  //Set Gamma
//    LCD_WR_DATA(0x0F);
//    LCD_WR_DATA(0x2A);
//    LCD_WR_DATA(0x28);
//    LCD_WR_DATA(0x08);
//    LCD_WR_DATA(0x0E);
//    LCD_WR_DATA(0x08);
//    LCD_WR_DATA(0x54);
//    LCD_WR_DATA(0XA9);
//    LCD_WR_DATA(0x43);
//    LCD_WR_DATA(0x0A);
//    LCD_WR_DATA(0x0F);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_REG(0XE1);  //Set Gamma
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x15);
//    LCD_WR_DATA(0x17);
//    LCD_WR_DATA(0x07);
//    LCD_WR_DATA(0x11);
//    LCD_WR_DATA(0x06);
//    LCD_WR_DATA(0x2B);
//    LCD_WR_DATA(0x56);
//    LCD_WR_DATA(0x3C);
//    LCD_WR_DATA(0x05);
//    LCD_WR_DATA(0x10);
//    LCD_WR_DATA(0x0F);
//    LCD_WR_DATA(0x3F);
//    LCD_WR_DATA(0x3F);
//    LCD_WR_DATA(0x0F);
//    LCD_WR_REG(0x2B);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x01);
//    LCD_WR_DATA(0x3f);
//    LCD_WR_REG(0x2A);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0x00);
//    LCD_WR_DATA(0xef);
//    LCD_WR_REG(0x11);  //Exit Sleep
//    Delay_Ms(120);
//    LCD_WR_REG(0x29);  //display on
//
//    LCD_direction(USE_HORIZONTAL);



    int cmd=0;
    const lcd_init_cmd_t* lcd_init_cmds;


    lcd_init_cmds = st7789_init_cmds;

    while (lcd_init_cmds[cmd].databytes!=0xff)
    {

        LCD_WR_REG(lcd_init_cmds[cmd].cmd);//дüÁ

        for(int i=0;i<lcd_init_cmds[cmd].databytes;i++)
        {
            LCD_WR_DATA(lcd_init_cmds[cmd].data[i]);//дʽ¾ݍ
        }
        if (lcd_init_cmds[cmd].databytes&0x80) {
            Delay_Ms(120); //ѓʱ
        }
        cmd++;
   }








    #endif


  #if GC9307


    LCD_WR_REG(0xec);
    LCD_WR_DATA(0x33);
    LCD_WR_DATA(0x02);
    LCD_WR_DATA(0x4c);

    LCD_WR_REG(0xfe);
    LCD_WR_REG(0xef);
    LCD_WR_REG(0x36);
    LCD_WR_DATA(0x48);

    LCD_WR_REG(0x3a);
    LCD_WR_DATA(0x05);

    LCD_WR_REG(0x86);
     LCD_WR_DATA(0x98);

     LCD_WR_REG(0xc9);
      LCD_WR_DATA(0x0a);

      LCD_WR_REG(0x89);
       LCD_WR_DATA(0x03);

       LCD_WR_REG(0xe8);
        LCD_WR_DATA(0x12);
        LCD_WR_DATA(0x00);

        LCD_WR_REG(0xc3);
         LCD_WR_DATA(0x45);

         LCD_WR_REG(0xc4);
          LCD_WR_DATA(0x20);

          LCD_WR_REG(0x8b);
           LCD_WR_DATA(0x80);
           LCD_WR_REG(0xff);
            LCD_WR_DATA(0x62);




LCD_WR_REG(0x8d);
LCD_WR_DATA(0x22);

LCD_WR_REG(0x99);
LCD_WR_DATA(0x3e);


LCD_WR_REG(0x9d);
LCD_WR_DATA(0x4b);

LCD_WR_REG(0x8e);
LCD_WR_DATA(0x0f);




LCD_WR_REG(0xf0);

LCD_WR_DATA(0x80);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x2f);


LCD_WR_REG(0xf1);
LCD_WR_DATA(0x44);
LCD_WR_DATA(0x99);
LCD_WR_DATA(0xb7);
LCD_WR_DATA(0x1b);
LCD_WR_DATA(0x1e);
LCD_WR_DATA(0xdf);


LCD_WR_REG(0xf2);
LCD_WR_DATA(0x43);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x0d);
LCD_WR_DATA(0x4f);


LCD_WR_REG(0xf3);
LCD_WR_DATA(0x60);
LCD_WR_DATA(0x76);
LCD_WR_DATA(0x78);
LCD_WR_DATA(0x2d);
LCD_WR_DATA(0x30);
LCD_WR_DATA(0x7f);



LCD_WR_REG(0x11);


Delay_Ms(120);

LCD_WR_REG(0x29);




















#endif
}

/*********************************************************************
 * @fn      LCD_SetWindows
 * 
 * @brief   Setting LCD display window
 * 
 * @param   xStar -  the bebinning x coordinate of the LCD display window
 *          yStar -  the bebinning y coordinate of the LCD display window
 *          xEnd -  the endning x coordinate of the LCD display window
 *          yEnd -  the endning y coordinate of the LCD display window
 * 
 * @return  none
 */
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{
    LCD_WR_REG(LCD_SET_X);
    LCD_WR_DATA(xStar >> 8);
    LCD_WR_DATA(0x00FF & xStar);
    LCD_WR_DATA(xEnd >> 8);
    LCD_WR_DATA(0x00FF & xEnd);

    LCD_WR_REG(LCD_SET_Y);

#if ST7789
    LCD_WR_DATA((yStar +20) >> 8);
    LCD_WR_DATA(0x00FF & (yStar +20));
    LCD_WR_DATA((yEnd +20)>> 8);
    LCD_WR_DATA(0x00FF & (yEnd +20));
#endif
#if  GC9307
    LCD_WR_DATA(yStar >> 8);
    LCD_WR_DATA(0x00FF & yStar);
    LCD_WR_DATA(yEnd >> 8);
    LCD_WR_DATA(0x00FF & yEnd);

#endif


    LCD_WR_REG(LCD_MEM_WRITE);  
}

/*********************************************************************
 * @fn      LCD_direction
 * 
 * @brief   Setting the display direction of LCD screen
 * 
 * @param   direction -   direction:0-0 degree  1-90 degree  2-180 degree  3-270 degree
 * 
 * @return  none
 */
void LCD_direction(uint8_t direction)
{
    switch (direction)
    {
        case 0:
            width  = LCD_W;
            height = LCD_H;
            LCD_WriteReg(0x36, (1 << 3) | (0 << 6) | (0 << 7));  //BGR==1,MY==0,MX==0,MV==0
            break;
        case 1:
            width  = LCD_H;
            height = LCD_W;
            LCD_WriteReg(0x36, (1 << 3) | (0 << 7) | (1 << 6) | (1 << 5));  //BGR==1,MY==1,MX==0,MV==1
            break;
        case 2:
            width  = LCD_W;
            height = LCD_H;
            LCD_WriteReg(0x36, (1 << 3) | (1 << 6) | (1 << 7));  //BGR==1,MY==0,MX==0,MV==0
            break;
        case 3:
            width  = LCD_H;
            height = LCD_W;
            LCD_WriteReg(0x36, (1 << 3) | (1 << 7) | (1 << 5));  //BGR==1,MY==1,MX==0,MV==1
            break;
        default:
            break;
    }
}

/*********************************************************************
 * @fn      LCD_Clear
 * 
 * @brief   Full screen filled LCD screen
 * 
 * @param   Color -   Filled color
 * 
 * @return  none
 */
void LCD_Clear(uint16_t Color)
{
    unsigned int i, m;
    LCD_SetWindows(0, 0, width - 1, height - 1);
    LCD_CS_CLR;
    LCD_DC_SET;
    for (i = 0; i < height; i++)
    {
        for (m = 0; m < width; m++)
        {
            Lcd_WriteData_16Bit(Color);
        }
    }
    LCD_CS_SET;
}

/*********************************************************************
 * @fn      LCD_drawImageWithSize
 * 
 * @brief   read image from SPI Flash and display on the LCD screen
 * 
 * @param   x -  the x coordinate of the LCD screen
 *          y - the y coordinate of the LCD screen
 *          width -  the image width
 *          height - the image height
 *          addr - the image address in SPI flash
 * 
 * @return  none
 */
void LCD_drawImageWithSize(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t addr)
{
    uint32_t m  = 0;
    uint16_t x2 = (x + width) - 1;
    uint16_t y2 = (y + height) - 1;
    LCD_WR_REG(LCD_SET_X);
    LCD_WR_DATA(x >> 8);
    LCD_WR_DATA(0x00FF & x);
    LCD_WR_DATA(x2 >> 8);
    LCD_WR_DATA(0x00FF & x2);

    LCD_WR_REG(LCD_SET_Y);
    LCD_WR_DATA(y >> 8);
    LCD_WR_DATA(0x00FF & y);
    LCD_WR_DATA(y2 >> 8);
    LCD_WR_DATA(0x00FF & y2);

    LCD_WR_REG(LCD_MEM_WRITE);
    LCD_CS_CLR;
    LCD_DC_SET;

#if 0
    uint32_t count = width * height;

    uint32_t fill_count = count / FILL_BUFFER_COUNT;
    uint32_t else_count = count % FILL_BUFFER_COUNT;
    SPI_Flash_Read_dma_start(addr);

    SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);

    while (fill_count > 0)
    {
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
            ;
        fill_count--;
        SPI2_Write_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
        m = !m;
        SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
    }
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
        ;
    SPI2_Write_DMA((uint8_t *)color_buffer[m], else_count * COLOR_BYTE);
    SPI_Flash_Read_dma_end();

#else



#endif
}






void LCD_Display_8bit(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t *data)
{
    uint32_t m  = 0;
    uint16_t x2 = (x + width) - 1;
    uint16_t y2 = (y + height) - 1;
    LCD_WR_REG(LCD_SET_X);
    LCD_WR_DATA(x >> 8);
    LCD_WR_DATA(0x00FF & x);
    LCD_WR_DATA(x2 >> 8);
    LCD_WR_DATA(0x00FF & x2);


    LCD_WR_REG(LCD_SET_Y);
#if ST7789
    LCD_WR_DATA((y +20) >> 8);
    LCD_WR_DATA(0x00FF & (y +20));
    LCD_WR_DATA((y2 +20)>> 8);
    LCD_WR_DATA(0x00FF & (y2 +20));
#endif
#if  GC9307
    LCD_WR_DATA(yStar >> 8);
    LCD_WR_DATA(0x00FF & yStar);
    LCD_WR_DATA(yEnd >> 8);
    LCD_WR_DATA(0x00FF & yEnd);

#endif


    LCD_WR_REG(LCD_MEM_WRITE);


#if 0
    uint32_t count = width * height;

    uint32_t fill_count = count / FILL_BUFFER_COUNT;
    uint32_t else_count = count % FILL_BUFFER_COUNT;
    SPI_Flash_Read_dma_start(addr);

    SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);

    while (fill_count > 0)
    {
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
            ;
        fill_count--;
        SPI2_Write_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
        m = !m;
        SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
    }
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
        ;
    SPI2_Write_DMA((uint8_t *)color_buffer[m], else_count * COLOR_BYTE);
    SPI_Flash_Read_dma_end();

#else

    #if 0  //
    for(int count = 0;count < width*height;count++){
        uint16_t lcd_data = *data;
        LCD_WR_DATA((lcd_data>>8)&0xff);
        LCD_WR_DATA((lcd_data>>0)&0xff);
        data++;
    }
    #else  //DMA

//        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
//        ;


#if !SPI_DMA_INT_ENABLE

    SPI_Cmd(SPI1, DISABLE);

    SPI1->CTLR1 |= (1<<11); //置为16bit 数据模式

    SPI_Cmd(SPI1, ENABLE);

    LCD_CS_CLR;
    LCD_DC_SET;


    DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);

    SPI1_DMA_TX_CH->MADDR = (uint32_t)data;
    SPI1_DMA_TX_CH->CNTR  = width*height;

    DMA_Cmd(SPI1_DMA_TX_CH, ENABLE);


    while(!DMA_GetFlagStatus(SPI1_DMA_TC_FLAG));

    DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);
    DMA_ClearFlag(SPI1_DMA_TC_FLAG);

    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));


    SPI_Cmd(SPI1, DISABLE);
    SPI1->CTLR1 &= ~(1<<11);
    SPI_Cmd(SPI1, ENABLE);
    LCD_CS_SET;
    LCD_DC_CLR;
    #else


    SPI_Cmd(SPI1, DISABLE);

    SPI1->CTLR1 |= (1<<11); //置为16bit 数据模式

    SPI_Cmd(SPI1, ENABLE);


    LCD_CS_CLR;
    LCD_DC_SET;

    DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);

    SPI1_DMA_TX_CH->MADDR = (uint32_t)data;
    SPI1_DMA_TX_CH->CNTR  = width*height;

    DMA_Cmd(SPI1_DMA_TX_CH, ENABLE);

#endif


    #endif



#endif
}


void LCD_Display_16bit(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t *data)
{
    uint32_t m  = 0;
    uint16_t x2 = (x + width) - 1;
    uint16_t y2 = (y + height) - 1;
    LCD_WR_REG(LCD_SET_X);
    LCD_WR_DATA(x >> 8);
    LCD_WR_DATA(0x00FF & x);
    LCD_WR_DATA(x2 >> 8);
    LCD_WR_DATA(0x00FF & x2);


    LCD_WR_REG(LCD_SET_Y);
#if ST7789
    LCD_WR_DATA((y +20) >> 8);
    LCD_WR_DATA(0x00FF & (y +20));
    LCD_WR_DATA((y2 +20)>> 8);
    LCD_WR_DATA(0x00FF & (y2 +20));
#endif
#if  GC9307
    LCD_WR_DATA(yStar >> 8);
    LCD_WR_DATA(0x00FF & yStar);
    LCD_WR_DATA(yEnd >> 8);
    LCD_WR_DATA(0x00FF & yEnd);

#endif


    LCD_WR_REG(LCD_MEM_WRITE);


#if 0
    uint32_t count = width * height;

    uint32_t fill_count = count / FILL_BUFFER_COUNT;
    uint32_t else_count = count % FILL_BUFFER_COUNT;
    SPI_Flash_Read_dma_start(addr);

    SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);

    while (fill_count > 0)
    {
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
            ;
        fill_count--;
        SPI2_Write_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
        m = !m;
        SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
    }
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
        ;
    SPI2_Write_DMA((uint8_t *)color_buffer[m], else_count * COLOR_BYTE);
    SPI_Flash_Read_dma_end();

#else

    #if 0  //
    for(int count = 0;count < width*height;count++){
        uint16_t lcd_data = *data;
        LCD_WR_DATA((lcd_data>>8)&0xff);
        LCD_WR_DATA((lcd_data>>0)&0xff);
        data++;
    }
    #else  //DMA

//        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
//        ;


#if !SPI_DMA_INT_ENABLE

    SPI_Cmd(SPI1, DISABLE);

    SPI1->CTLR1 |= (1<<11); //置为16bit 数据模式

    SPI_Cmd(SPI1, ENABLE);

    LCD_CS_CLR;
    LCD_DC_SET;


    DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);

    SPI1_DMA_TX_CH->MADDR = (uint32_t)data;
    SPI1_DMA_TX_CH->CNTR  = width*height;

    DMA_Cmd(SPI1_DMA_TX_CH, ENABLE);


    while(!DMA_GetFlagStatus(SPI1_DMA_TC_FLAG));

    DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);
    DMA_ClearFlag(SPI1_DMA_TC_FLAG);

    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));


    SPI_Cmd(SPI1, DISABLE);
    SPI1->CTLR1 &= ~(1<<11);
    SPI_Cmd(SPI1, ENABLE);
    LCD_CS_SET;
    LCD_DC_CLR;
    #else


    SPI_Cmd(SPI1, DISABLE);

    SPI1->CTLR1 |= (1<<11); //置为16bit 数据模式



    DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);

    SPI1_DMA_TX_CH->MADDR = (uint32_t)data;
    SPI1_DMA_TX_CH->CNTR  = (width*height);



      LCD_CS_CLR;
      LCD_DC_SET;
      SPI_Cmd(SPI1, ENABLE);
    DMA_Cmd(SPI1_DMA_TX_CH, ENABLE);

#endif


    #endif

 

#endif
}



void LCD_Display(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t *data)
{
    uint32_t m  = 0;
    uint16_t x2 = (x + width) - 1;
    uint16_t y2 = (y + height) - 1;
    LCD_WR_REG(LCD_SET_X);
    LCD_WR_DATA(x >> 8);
    LCD_WR_DATA(0x00FF & x);
    LCD_WR_DATA(x2 >> 8);
    LCD_WR_DATA(0x00FF & x2);


    LCD_WR_REG(LCD_SET_Y);
#if ST7789
    LCD_WR_DATA((y +20) >> 8);
    LCD_WR_DATA(0x00FF & (y +20));
    LCD_WR_DATA((y2 +20)>> 8);
    LCD_WR_DATA(0x00FF & (y2 +20));
#endif
#if  GC9307
    LCD_WR_DATA(yStar >> 8);
    LCD_WR_DATA(0x00FF & yStar);
    LCD_WR_DATA(yEnd >> 8);
    LCD_WR_DATA(0x00FF & yEnd);

#endif


    LCD_WR_REG(LCD_MEM_WRITE);
    LCD_CS_CLR;
    LCD_DC_SET;

#if 0
    uint32_t count = width * height;

    uint32_t fill_count = count / FILL_BUFFER_COUNT;
    uint32_t else_count = count % FILL_BUFFER_COUNT;
    SPI_Flash_Read_dma_start(addr);

    SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);

    while (fill_count > 0)
    {
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
            ;
        fill_count--;
        SPI2_Write_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
        m = !m;
        SPI1_Read_DMA((uint8_t *)color_buffer[m], FILL_BUFFER_SIZE);
    }
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
        ;
    SPI2_Write_DMA((uint8_t *)color_buffer[m], else_count * COLOR_BYTE);
    SPI_Flash_Read_dma_end();

#else

    #if 0  //
    for(int count = 0;count < width*height;count++){
        uint16_t lcd_data = *data;
        LCD_WR_DATA((lcd_data>>8)&0xff);
        LCD_WR_DATA((lcd_data>>0)&0xff);
        data++;
    }
    #else  //DMA 

    SPI2_Write_DMA(data, width*height);


    #endif

    LCD_CS_SET;
    LCD_DC_CLR;

#endif
}





__attribute__((interrupt("WCH-Interrupt-fast"))) void DMA1_Channel3_IRQHandler(void){
   // printf("1");


   // while(!DMA_GetFlagStatus(SPI1_DMA_TC_FLAG));
    if(DMA_GetITStatus(SPI1_DMA_TC_IT)){
        while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));

        DMA_ClearITPendingBit(SPI1_DMA_TC_IT);
        DMA_Cmd(SPI1_DMA_TX_CH, DISABLE);
        //DMA_ClearFlag(SPI1_DMA_TC_FLAG);


        SPI_Cmd(SPI1, DISABLE);
        SPI1->CTLR1 &= ~(1<<11);
        //SPI_Cmd(SPI1, ENABLE);
        SPI_Cmd(SPI1, ENABLE);


        //printf("2");



        disp_adapter0_insert_async_flushing_complete_event_handler();


        LCD_CS_SET;
        LCD_DC_CLR;
    }
}
